﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections;

namespace MetaProperties.Collections.Tests
{
    using System;

    using Collections;


    /// <summary>
    ///This is a test class for ObservableListTest and is intended
    ///to contain all ObservableListTest Unit Tests
    ///</summary>
    [TestClass()]
    public class ObservableListTest
    {
        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        ///////// <summary>
        /////////A test for SurpressChangedEvents
        /////////</summary>
        //////public void SurpressChangedEventsTestHelper<ItemT>()
        //////{
        //////    ObservableList<ItemT> list = new ObservableList<ItemT>();
        //////    PrivateObject param0 = new PrivateObject(list);
        //////    ObservableList_Accessor<ItemT> target = new ObservableList_Accessor<ItemT>(param0);

        //////    Assert.IsFalse(target.SurpressChangedEvents);
        //////    target.SurpressChangedEvents = true;
        //////    Assert.IsTrue(target.SurpressChangedEvents);

        //////    bool collectionChangedCalled = false;
        //////    list.CollectionChanged += (s, e) => collectionChangedCalled = true;
        //////    list.Add(default(ItemT));
        //////    Assert.IsFalse(collectionChangedCalled);

        //////    target.SurpressChangedEvents = false;
        //////    list.Add(default(ItemT));
        //////    Assert.IsTrue(collectionChangedCalled);
        //////}

        //////[TestMethod()]
        //////[DeploymentItem("MetaProperties.Core.dll")]
        //////public void SurpressChangedEventsTest()
        //////{
        //////    SurpressChangedEventsTestHelper<GenericParameterHelper>();
        //////}

        /// <summary>
        ///A test for Item
        ///</summary>
        public void ItemTestHelper<ItemT>(ItemT value)
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            int index = 0;
            ItemT expected = value;
            ItemT actual;

            bool outOfRangeExceptionThrown = false;
            try
            {
                target[index] = expected;
            }
            catch (ArgumentOutOfRangeException)
            {
                outOfRangeExceptionThrown = true;
            }

            Assert.IsTrue(outOfRangeExceptionThrown);

            target.Add(default(ItemT));

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Replace, args.Action);
                Assert.AreEqual(default(ItemT), args.OldItems[0]);
                Assert.AreEqual(0, args.OldStartingIndex);
                Assert.AreEqual(0, args.NewStartingIndex);
                Assert.AreEqual(expected, args.NewItems[0]);
            };

            target[index] = expected;

            Assert.IsTrue(collectionChangedCalled);

            actual = target[index];

            Assert.AreEqual(expected, actual);
        }

        [TestMethod()]
        public void ItemTest()
        {
            ItemTestHelper<GenericParameterHelper>(new GenericParameterHelper(5));
        }

        /// <summary>
        ///A test for IsReadOnly
        ///</summary>
        public void IsReadOnlyTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            Assert.IsFalse(target.IsReadOnly);
        }

        [TestMethod()]
        public void IsReadOnlyTest()
        {
            IsReadOnlyTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Count
        ///</summary>
        public void CountTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            Assert.AreEqual(0, target.Count);
            target.Add(default(ItemT));
            Assert.AreEqual(1, target.Count);
            target.RemoveAt(0);
            Assert.AreEqual(0, target.Count);
        }

        [TestMethod()]
        public void CountTest()
        {
            CountTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for ToArray
        ///</summary>
        public void ToArrayTestHelper<ItemT>(params ItemT[] items)
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>(items);
            ItemT[] expected = items;
            ItemT[] actual = target.ToArray();

            Assert.AreEqual(expected.Length, actual.Length);

            for (int i = 0; i < actual.Length; i++)
            {
                Assert.AreEqual(expected[i], actual[i]);
            }
        }

        [TestMethod()]
        public void ToArrayTest()
        {
            ToArrayTestHelper<GenericParameterHelper>(
                new GenericParameterHelper(5),
                new GenericParameterHelper(2),
                new GenericParameterHelper(7));
        }

        /// <summary>
        ///A test for System.Collections.IEnumerable.GetEnumerator
        ///</summary>
        public void GetEnumeratorTest1Helper<ItemT>()
        {
            IEnumerable target = new ObservableList<ItemT>(new[] { default(ItemT) });
            IEnumerator actual = target.GetEnumerator();
            Assert.IsNotNull(actual);
            Assert.IsTrue(actual.MoveNext());
            Assert.IsFalse(actual.MoveNext());
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void GetEnumeratorTest1()
        {
            GetEnumeratorTest1Helper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for RemoveAt
        ///</summary>
        public void RemoveAtTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            int index = 0;

            bool outOfRangeExceptionThrown = false;
            try
            {
                target.RemoveAt(index);
            }
            catch (ArgumentOutOfRangeException)
            {
                outOfRangeExceptionThrown = true;
            }

            Assert.IsTrue(outOfRangeExceptionThrown);

            target.Add(default(ItemT));
            target.Add(default(ItemT));
            Assert.AreEqual(2, target.Count);

            index = 1;

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Remove, args.Action);
                Assert.AreEqual(default(ItemT), args.OldItems[0]);
                Assert.AreEqual(null, args.NewItems);
                Assert.AreEqual(1, args.OldStartingIndex);
                Assert.AreEqual(-1, args.NewStartingIndex);
            };

            target.RemoveAt(index);

            Assert.IsTrue(collectionChangedCalled);

            Assert.AreEqual(1, target.Count);
        }

        [TestMethod()]
        public void RemoveAtTest()
        {
            RemoveAtTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Remove
        ///</summary>
        public void RemoveTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            ItemT value = default(ItemT);

            Assert.IsFalse(target.Remove(value));

            target.Add(value);

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Remove, args.Action);
                Assert.AreEqual(default(ItemT), args.OldItems[0]);
                Assert.AreEqual(null, args.NewItems);
                Assert.AreEqual(0, args.OldStartingIndex);
                Assert.AreEqual(-1, args.NewStartingIndex);
            };

            Assert.IsTrue(target.Remove(value));
            Assert.IsTrue(collectionChangedCalled);
        }

        [TestMethod()]
        public void RemoveTest()
        {
            RemoveTestHelper<GenericParameterHelper>();
        }

        ///////// <summary>
        /////////A test for OnCollectionChanged
        /////////</summary>
        //////public void OnCollectionChangedTestHelper<ItemT>()
        //////{
        //////    ObservableList<ItemT> list = new ObservableList<ItemT>();
        //////    PrivateObject param0 = new PrivateObject(list);
        //////    ObservableList_Accessor<ItemT> target = new ObservableList_Accessor<ItemT>(param0);
        //////    NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);

        //////    bool collectionChangedCalled = false;

        //////    list.CollectionChanged += (s, args) =>
        //////        {
        //////            collectionChangedCalled = true;
        //////            Assert.AreEqual(list, s);
        //////            Assert.AreEqual(e, args);
        //////        };

        //////    target.SurpressChangedEvents = true;
        //////    target.OnCollectionChanged(e);
        //////    Assert.IsTrue(collectionChangedCalled);

        //////    collectionChangedCalled = false;

        //////    target.SurpressChangedEvents = false;
        //////    target.OnCollectionChanged(e);
        //////    Assert.IsTrue(collectionChangedCalled);
        //////}

        //////[TestMethod()]
        //////[DeploymentItem("MetaProperties.Core.dll")]
        //////public void OnCollectionChangedTest()
        //////{
        //////    OnCollectionChangedTestHelper<GenericParameterHelper>();
        //////}

        /// <summary>
        ///A test for Insert
        ///</summary>
        public void InsertTestHelper<ItemT>(
            ItemT item1, 
            ItemT item2, 
            ItemT item3)
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();

            bool outOfRangeExceptionThrown = false;
            try
            {
                target.Insert(1, item1);
            }
            catch (ArgumentOutOfRangeException)
            {
                outOfRangeExceptionThrown = true;
            }

            Assert.IsTrue(outOfRangeExceptionThrown);

            target.Insert(0, item1);

            Assert.AreEqual(1, target.Count);
            Assert.AreEqual(item1, target[0]);

            target.Insert(1, item2);

            Assert.AreEqual(2, target.Count);
            Assert.AreEqual(item1, target[0]);
            Assert.AreEqual(item2, target[1]);

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Add, args.Action);
                Assert.AreEqual(item3, args.NewItems[0]);
                Assert.AreEqual(null, args.OldItems);
                Assert.AreEqual(0, args.NewStartingIndex);
                Assert.AreEqual(-1, args.OldStartingIndex);
            };

            target.Insert(0, item3);

            Assert.IsTrue(collectionChangedCalled);

            Assert.AreEqual(3, target.Count);
            Assert.AreEqual(item3, target[0]);
            Assert.AreEqual(item1, target[1]);
            Assert.AreEqual(item2, target[2]);
        }

        [TestMethod()]
        public void InsertTest()
        {
            InsertTestHelper<GenericParameterHelper>(
                new GenericParameterHelper(5),
                new GenericParameterHelper(7),
                new GenericParameterHelper(1));
        }

        /// <summary>
        ///A test for IndexOf
        ///</summary>
        public void IndexOfTestHelper<ItemT>(
            ItemT item1,
            ItemT item2,
            ItemT item3)
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>(
                new[] { item1, item2, item3 });

            Assert.AreEqual(1, target.IndexOf(item2));
            Assert.AreEqual(0, target.IndexOf(item1));
            Assert.AreEqual(2, target.IndexOf(item3));
            Assert.AreEqual(-1, target.IndexOf(default(ItemT)));
        }

        [TestMethod()]
        public void IndexOfTest()
        {
            IndexOfTestHelper<GenericParameterHelper>(
                new GenericParameterHelper(5),
                new GenericParameterHelper(7),
                new GenericParameterHelper(1));
        }

        /// <summary>
        ///A test for GetEnumerator
        ///</summary>
        public void GetEnumeratorTestHelper<ItemT>()
        {
            IEnumerable<ItemT> target = new ObservableList<ItemT>(new[] { default(ItemT) });
            IEnumerator<ItemT> actual = target.GetEnumerator();
            Assert.IsNotNull(actual);
            Assert.IsTrue(actual.MoveNext());
            Assert.IsFalse(actual.MoveNext());
        }

        [TestMethod()]
        public void GetEnumeratorTest()
        {
            GetEnumeratorTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for CopyTo
        ///</summary>
        public void CopyToTestHelper<ItemT>(params ItemT[] items)
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>(items);
            ItemT[] array = new ItemT[5];
            int arrayIndex = 1;
            target.CopyTo(array, arrayIndex);

            for (int i = 0; i < target.Count; i++)
            {
                Assert.AreEqual(target[i], array[i + 1]);
            }

            Assert.AreEqual(default(ItemT), array[0]);
            Assert.AreEqual(default(ItemT), array[array.Length - 1]);
        }

        [TestMethod()]
        public void CopyToTest()
        {
            CopyToTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Contains
        ///</summary>
        public void ContainsTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            ItemT item = default(ItemT);

            Assert.IsFalse(target.Contains(item));

            target.Add(item);

            Assert.IsTrue(target.Contains(item));
        }

        [TestMethod()]
        public void ContainsTest()
        {
            ContainsTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Clear
        ///</summary>
        public void ClearTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>
            {
                default(ItemT),
                default(ItemT),
            };

            Assert.AreEqual(2, target.Count);

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Remove, args.Action);
                Assert.AreEqual(null, args.NewItems);
                Assert.AreEqual(2, args.OldItems.Count);
                Assert.AreEqual(0, args.OldStartingIndex);
                Assert.AreEqual(-1, args.NewStartingIndex);
            };

            target.Clear();

            Assert.IsTrue(collectionChangedCalled);

            Assert.AreEqual(0, target.Count);
        }

        [TestMethod()]
        public void ClearTest()
        {
            ClearTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Add
        ///</summary>
        public void AddTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();

            Assert.AreEqual(0, target.Count);

            target.Add(default(ItemT));

            Assert.AreEqual(1, target.Count);

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Add, args.Action);
                Assert.AreEqual(default(ItemT), args.NewItems[0]);
                Assert.AreEqual(1, args.NewItems.Count);
                Assert.AreEqual(1, args.NewStartingIndex);
                Assert.AreEqual(null, args.OldItems);
                Assert.AreEqual(-1, args.OldStartingIndex);
            };

            target.Add(default(ItemT));

            Assert.IsTrue(collectionChangedCalled);

            Assert.AreEqual(2, target.Count);
        }

        [TestMethod()]
        public void AddTest()
        {
            AddTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for AddRange
        ///</summary>
        public void AddRangeTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            ItemT[] items = new[] { default(ItemT), default(ItemT) };

            Assert.AreEqual(0, target.Count);

            bool collectionChangedCalled = false;
            target.CollectionChanged += (s, args) =>
            {
                collectionChangedCalled = true;
                Assert.AreEqual(target, s);
                Assert.AreEqual(NotifyCollectionChangedAction.Add, args.Action);
                Assert.AreEqual(2, args.NewItems.Count);
                Assert.AreEqual(default(ItemT), args.NewItems[0]);
                Assert.AreEqual(default(ItemT), args.NewItems[1]);
                Assert.AreEqual(0, args.NewStartingIndex);
                Assert.AreEqual(-1, args.OldStartingIndex);
                Assert.AreEqual(null, args.OldItems);
            };

            target.AddRange(items);

            Assert.IsTrue(collectionChangedCalled);

            Assert.AreEqual(2, target.Count);
        }

        [TestMethod()]
        public void AddRangeTest()
        {
            AddRangeTestHelper<GenericParameterHelper>();
        }

        ///////// <summary>
        /////////A test for _items_CollectionChanged
        /////////</summary>
        //////public void Items_CollectionChangedTestHelper<ItemT>()
        //////{
        //////    ObservableList<ItemT> list = new ObservableList<ItemT>();
        //////    PrivateObject param0 = new PrivateObject(list);
        //////    ObservableList_Accessor<ItemT> target = new ObservableList_Accessor<ItemT>(param0);

        //////    object sender = this;
        //////    NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);

        //////    bool collectionChangedCalled = false;
        //////    list.CollectionChanged += (s, args) =>
        //////        {
        //////            collectionChangedCalled = true;
        //////            Assert.AreEqual(list, s);
        //////            Assert.AreEqual(e, args);
        //////        };

        //////    target.SurpressChangedEvents = true;
        //////    target.Items_CollectionChanged(sender, e);
        //////    Assert.IsFalse(collectionChangedCalled);

        //////    collectionChangedCalled = false;

        //////    target.SurpressChangedEvents = false;
        //////    target.Items_CollectionChanged(sender, e);
        //////    Assert.IsTrue(collectionChangedCalled);
        //////}

        //////[TestMethod()]
        //////[DeploymentItem("MetaProperties.Core.dll")]
        //////public void Items_CollectionChangedTest()
        //////{
        //////    Items_CollectionChangedTestHelper<GenericParameterHelper>();
        //////}

        /// <summary>
        ///A test for ObservableList`1 Constructor
        ///</summary>
        public void ObservableListConstructorTestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>();
            Assert.AreEqual(0, target.Count);
        }

        [TestMethod()]
        public void ObservableListConstructorTest()
        {
            ObservableListConstructorTestHelper<GenericParameterHelper>();
        }
        
        /// <summary>
        ///A test for ObservableList`1 Constructor
        ///</summary>
        public void ObservableListConstructor1TestHelper<ItemT>()
        {
            ObservableList<ItemT> target = new ObservableList<ItemT>(new[] { default(ItemT), default(ItemT) });
            Assert.AreEqual(2, target.Count);
        }

        [TestMethod()]
        public void ObservableListConstructor1Test()
        {
            ObservableListConstructor1TestHelper<GenericParameterHelper>();
        }
    }
}
